 /*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 /**
 * Project  : EasyAvatar-Lib
 * Package  : net.solosky.easyavatar.api.impl
 * File     : XiaoyouFriendProvider.java
 * Author   : solosky < solosky772@qq.com >
 * Created  : Oct 30, 2011
 * License  : Apache License 2.0 
 */
package net.solosky.easyavatar.api.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.solosky.easyavatar.api.ApiException;
import net.solosky.easyavatar.api.Avatar;
import net.solosky.easyavatar.api.Avatar.Scale;
import net.solosky.easyavatar.api.ErrorCode;
import net.solosky.easyavatar.api.Friend;
import net.solosky.easyavatar.api.FriendList;
import net.solosky.easyavatar.api.Group;
import net.solosky.easyavatar.api.http.HttpRequest;
import net.solosky.easyavatar.api.http.HttpResponse;
import net.solosky.easyavatar.api.util.QQEncryptor;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 *
 * QQ朋友好友提供者
 *
 * @author solosky <solosky772@qq.com>
 *
 */
@SuppressWarnings("unchecked")
public class PengyouFriendProvider extends AbstractQQServiceFriendProvider{
	private static final String URL_MYFRIENDS = "http://mix.pengyou.com/index.php?mod=friends&act=manage";
	private static final String URL_MYINFO    = "http://www.pengyou.com/index.php?mod=userinfo"; 
	private static final String URL_MAYKOWNS  = "http://friend.pengyou.com/index.php?mod=friends&act=mayknow";
	private static final String URL_API       = "http://api.pengyou.com/index.php";
	private static final String URL_AVATAR    = "http://py.qlogo.cn/friend/%s/audited/%s";
	/**可能认识人Hash列表*/
	private List<String> mayKnownIds;
	
	public PengyouFriendProvider(){
		mayKnownIds = new ArrayList<String>();
	}

	@Override
	public void init() throws ApiException, IOException {
	}

	@Override
	public FriendList retireMyFriends(String index) throws ApiException,
			IOException {
		HttpRequest  req = createHttpRequest(URL_MYFRIENDS, "GET");
		HttpResponse res = executeHttpRequest(req);
		validateResponse(res);
		
		String html = res.getResponseString();
		String body = substring(html, "module.friends.Manage.setData(", ");");
		try {
			JSONObject json = new JSONObject(body);
			FriendList friendList = new FriendList();
			friendList.setHasGroup(true);
			friendList.setHasNext(false);
			friendList.setNextIndex(null);
			
			JSONObject groups = json.getJSONObject("group_list");
			Iterator<String>  it = groups.keys();
			while(it.hasNext()){
				String key = it.next();
				JSONObject entry = groups.getJSONObject(key);
				Group group = new Group();
				group.setGid(key);
				group.setName(entry.getString("name"));
				friendList.getGroups().add(group);
			}
			
			JSONObject friends = json.getJSONObject("friends_list");
			it = friends.keys();
			while(it.hasNext()){
				JSONObject entry = friends.getJSONObject(it.next());
				Friend friend = new Friend();
				friend.setFid(entry.getString("hash"));
				friend.setGid(entry.optString("groupid"));
				friend.setName(entry.getString("realname"));
				friend.getAvatar().setUrl(entry.getString("logo"));
				friendList.getFriends().add(friend);
			}
			
			return friendList;
		} catch (JSONException e) {
			throw new ApiException(ErrorCode.INVALID_RESPONSE, e);
		}
	}

	@Override
	public FriendList retireMayKnowns(String index) throws ApiException,
			IOException {
		
		HttpRequest req = null;
		HttpResponse res = null;
		
		//判断是否是第一次获取，如果是，获取可能认识的Hash列表
		if(index==null){
			req = createHttpRequest(URL_MAYKOWNS, "GET");
			res = executeHttpRequest(req);
			validateResponse(res);
			
			String html = res.getResponseString();
			String body = substring(html, "var g_userHashes =", ";");
			try {
				JSONObject json = new JSONObject(body);
				Iterator<String> it = json.keys();
				mayKnownIds.clear();
				while(it.hasNext()){
					mayKnownIds.add(it.next());
				}
			} catch (JSONException e) {
				throw new ApiException(ErrorCode.INVALID_RESPONSE, e);
			}
			
			index = "0";
		}
		
		//根据传递来的Index来获取部分好友信息
		int offset   = Integer.parseInt(index);
		int batchNum = 20;
		if(offset>=mayKnownIds.size())	throw new ApiException(ErrorCode.NO_MORE_FIRENDS);
		
		int min = Math.min(batchNum, mayKnownIds.size());
		StringBuffer buffer = new StringBuffer();
		for(int i=offset; i<min; i++){
			buffer.append(mayKnownIds.get(i));
			if(i+1<min)
				buffer.append(",");
		}
		
		String skey = getHttpClient().getCookie("skey").getValue();
		String gtk = QQEncryptor.gtk(skey);
		
		req = createHttpRequest(URL_API, "POST");
		req.addPostValue("_skey", skey);
		req.addPostValue("g_tk", gtk);
		req.addPostValue("mod", "friends");
		req.addPostValue("act", "get_info_by_hash");
		req.addPostValue("token_uin", getUin());
		req.addPostValue("bai_ck", Math.random()+"");
		req.addPostValue("sync_request", "1");
		req.addPostValue("user_hash", buffer.toString());
		
		res = executeHttpRequest(req);
		validateResponse(res);
		
		try {
			JSONObject json = new JSONObject(res.getResponseString());
			if(json.getInt("err")!=0) throw new ApiException(ErrorCode.INVALID_RESPONSE);
			
			FriendList friendList = new FriendList();
			friendList.setHasGroup(false);
			friendList.setHasNext(min!=mayKnownIds.size());
			friendList.setNextIndex(min+"");
			
			JSONArray knowns = json.getJSONArray("result");
			for(int i=0; i<knowns.length(); i++){
				JSONObject entry = knowns.getJSONObject(i);
				Friend friend = new Friend();
				friend.setFid(entry.getString("hash"));
				friend.setName(entry.getString("realname"));
				friend.getAvatar().setUrl(entry.getString("logo"));
				friendList.getFriends().add(friend);
			}
			
			return friendList;
		} catch (JSONException e) {
			throw new ApiException(ErrorCode.INVALID_RESPONSE, e);
		}
	}

	@Override
	public Avatar retireFriendAvatar(Friend friend, Scale scale)
			throws ApiException, IOException {
		HttpRequest req = createHttpRequest(String.format(URL_AVATAR, friend.getFid(), scale==Scale.LARGE?"100":"50"), "GET");
		HttpResponse res = executeHttpRequest(req);
		if(res.getResponseCode()==HttpResponse.HTTP_OK){
			friend.getAvatar().setData(res.getResponseData());
			friend.getAvatar().setUrl(req.getUrl());
			return friend.getAvatar();
		}else{
			throw new ApiException(ErrorCode.NO_AVATAR);
		}
	}

	@Override
	public Avatar retireMyAvatar(Friend friend, Scale scale)
			throws ApiException, IOException {
		return retireFriendAvatar(friend, scale);
	}

	@Override
	public Friend retireMyInfo() throws ApiException, IOException {
		HttpRequest  req = createHttpRequest(URL_MYINFO, "GET");
		HttpResponse res = executeHttpRequest(req);
		validateResponse(res);
		
		String html = res.getResponseString();
		String body = substring(html, "new USER(", ");");
		try {
			JSONObject json = new JSONObject(body);
			Friend friend = new Friend();
			friend.setFid(json.getString("hash"));
			friend.setName(json.getString("name"));
			friend.getAvatar().setUrl(json.getString("logo"));
			return friend;
		} catch (JSONException e) {
			throw new ApiException(ErrorCode.INVALID_RESPONSE, e);
		}
	}

	@Override
	protected String getAppId() {
		return "15004601";
	}
	
	
	private String substring(String body, String start, String end) throws ApiException{
		int s = body.indexOf(start);
		int d = body.indexOf(end, s);
		if(s==-1 || d==-1)	throw new ApiException(ErrorCode.INVALID_RESPONSE);
		
		return body.substring(s+start.length(), d);
	}

}
